package com.hd.controller.activiti;

import com.hd.commons.annotation.LogAnnotation;
import com.hd.controller.activiti.util.hightline.DefaultProcessDiagramGenerator;
import com.hd.controller.base.BaseController;
import com.hd.entity.activiti.*;
import com.hd.entity.sys.User;
import com.hd.service.activiti.*;
import com.hd.service.sys.UserService;
import com.hd.util.StringUtils;
import com.hd.util.result.Page;
import com.hd.util.result.PageInfo;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.util.*;
import java.util.zip.ZipInputStream;

/**
 * 流程管理
 *
 * @author hzhh123 2018年7月31日下午1:45:35
 */
@Controller
@RequestMapping("/process")
public class ProcessController extends BaseController {
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private ActivitiService activitiService;
    @Autowired
    private UserService userService;
    @Autowired
    private UserTaskService userTaskService;
    @Autowired
    private ProcessInstanceEntityService processInstanceEntityService;
    @Autowired
    private ProcessTypeService processTypeService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private ProcessEngine processEngine;
    @Autowired
    private ProcessEngineConfiguration processEngineConfiguration;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private CommentEntityService commentEntityService;
    @Autowired
    private DeploymentEntityService deploymentEntityService;

    @RequestMapping("/todeploy")
    public String toDeploy() {
        return "jsp/activiti/deploy/deployList";
    }

    /**
     * 上传流程部署文件
     *
     * @param deployFile
     * @return
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping("/deploy")
    @LogAnnotation("部署流程文件")
    public Object addDeploy(@RequestParam("deployFile") MultipartFile deployFile) throws Exception {
        String name = deployFile.getOriginalFilename().substring(0, deployFile.getOriginalFilename().lastIndexOf("."));
        Deployment deploy = repositoryService.createDeployment() // 创建部署
                .name(name) // 流程名称
                .addZipInputStream(new ZipInputStream(deployFile.getInputStream())) // 添加zip输入流
                .deploy(); // 部署
        addDeploymentEntity(deploy.getId());
        addFlowType(deploy.getId());
        return renderSuccess("部署成功！");
    }
    /**
     * 保存流程类型
     * @param deploymentId
     */
    private void addFlowType(String deploymentId) {
    	  ProcessDefinition processDefinition=repositoryService.createProcessDefinitionQuery()
          		.deploymentId(deploymentId).singleResult();
    	  ProcessType p=new ProcessType();
    	  p.setDeploymentId(deploymentId);
    	  p.setIconCls("fi fi-folder");
    	  p.setProcdefid(processDefinition.getId());
    	  p.setVersion(""+processDefinition.getVersion());
    	  p.setKey(processDefinition.getKey());
    	  p.setName(processDefinition.getName());
    	  p.setType(1);
    	  p.setStatus(1);
    	  p.setSeq(0);
    	  processTypeService.save(p);
    }

    /**
     * 保存部署信息
     * @param deploymentId
     */
    public void addDeploymentEntity(String deploymentId){
        ProcessDefinition processDefinition=repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploymentId).singleResult();
        DeploymentEntity deploymentEntity=new DeploymentEntity();
        deploymentEntity.setDeploymentId(deploymentId);
        deploymentEntity.setKey(processDefinition.getKey());
        deploymentEntity.setProcDefId(processDefinition.getId());
        deploymentEntity.setDiagramResourceName(processDefinition.getDiagramResourceName());
        deploymentEntity.setResourceName(processDefinition.getResourceName());
        deploymentEntity.setVersion(processDefinition.getVersion()+"");
        deploymentEntityService.save(deploymentEntity);
    }
    /**
     * 删除流程部署
     *
     * @param ids
     * @return
     * @throws Exception
     */
    @ResponseBody
    @LogAnnotation("删除部署流程文件")
    @RequestMapping("/deploy/delete")
    public Object deleteDelop(@RequestParam(value = "ids", required = false) String ids) throws Exception {
        String[] idsStr = ids.split(",");
        for (int i = 0; i < idsStr.length; i++) {
            //true 级联删除流程实例
            deploymentEntityService.cancel(idsStr[i]);
            processTypeService.cancel(idsStr[i]);
        }
        return renderSuccess("删除成功！");
    }
//    @ResponseBody
//    @LogAnnotation("删除部署流程文件")
//    @RequestMapping("/deploy/delete")
//    public Object deleteDelop(@RequestParam(value = "ids", required = false) String ids) throws Exception {
//        String[] idsStr = ids.split(",");
//        for (int i = 0; i < idsStr.length; i++) {
//            //true 级联删除流程实例
//            repositoryService.deleteDeployment(idsStr[i], true);
//            processTypeService.delete(idsStr[i]);
//        }
//        return renderSuccess("删除成功！");
//    }

    /**
     * 查询部署分页
     *
     * @param name
     * @param page
     * @return
     */
    @ResponseBody
    @RequestMapping("dataGrid")
    public Object dataGrid(String name, Integer page, Integer rows, String sort, String order) {
        if (name == null) {
            name = "";
        }
        PageInfo info = new PageInfo(page, rows);
        // listPage方法与list方法类似，最终也是以主键升序排序返回结果集，与list方法不一样的是，listPage方法需要提供两个int参数，
        // 第一个参数数据的开始索引，从0开始，第二个参数为结果数量
        List<Deployment> deploymentList = repositoryService.createDeploymentQuery().deploymentNameLike("%" + name + "%")
                .orderByDeploymenTime().desc()// 根据时间降序查询
                .listPage((page - 1) * rows, rows);
        int total = repositoryService.createDeploymentQuery().deploymentNameLike("%" + name + "%")
                .orderByDeploymenTime().desc().list().size();
        // 这里有问题
        List<com.hd.entity.activiti.Deployment> deployments = new ArrayList<com.hd.entity.activiti.Deployment>();
        if (deploymentList.size() > 0) {
            for (Deployment deployment : deploymentList) {
                com.hd.entity.activiti.Deployment deployment1 = new com.hd.entity.activiti.Deployment();
                deployment1.setId(deployment.getId());
                deployment1.setCategory(deployment.getCategory());
                deployment1.setName(deployment.getName());
                deployment1.setTenantId(deployment.getTenantId());
                deployment1.setDeploymentTime(deployment.getDeploymentTime());
                deployments.add(deployment1);
            }
        }
        info.setRows(deployments);
        info.setTotal(total);
        return info;
    }

    /**
     * 查询部署后的流程定义列表
     *
     * @param page
     * @param rows
     * @return
     */
    @RequestMapping(value = "/listBpmn")
    @ResponseBody
    public Object listBpmn(Integer page, Integer rows,DeploymentEntity deploymentEntity) {
        if (page <= 0) {
            page = 1;
        }
        PageInfo p = new PageInfo(page, rows);
        Map<String,Object>condition=new HashMap<String,Object>();
        if(StringUtils.isNotNull(deploymentEntity.getName())){
            condition.put("name",deploymentEntity.getName());
        }
        p.setCondition(condition);
        deploymentEntityService.selectDataGrid(p);
        return p;
    }
//    @RequestMapping(value = "/listBpmn")
//    @ResponseBody
//    public Object listBpmn(Integer page, Integer rows) {
//        if (page <= 0) {
//            page = 1;
//        }
//        ProcessDefinitionQuery proDefQuery = repositoryService.createProcessDefinitionQuery().orderByDeploymentId()
//                .desc();
//        List<Object> jsonList = new ArrayList<Object>();
//        Integer totalSum = proDefQuery.list().size();
//        List<ProcessDefinition> processDefinitionList = proDefQuery.listPage((page - 1) * rows, rows);
//        for (ProcessDefinition pd : processDefinitionList) {
//            Map<String, Object> map = new HashMap<String, Object>();
//            map.put("procDefId", pd.getId());
//            map.put("name", pd.getName());
//            map.put("deploymentId", pd.getDeploymentId());
//            map.put("key", pd.getKey());
//            map.put("resourceName", pd.getResourceName());
//            map.put("diagramResourceName", pd.getDiagramResourceName());
//            map.put("version",pd.getVersion());
//            jsonList.add(map);
//        }
//        PageInfo p = new PageInfo(page, rows);
//        p.setRows(jsonList);
//        p.setTotal(totalSum);
//        return p;
//    }

    /**
     * 跳转到 配置任务节点页面
     *
     * @param processDefinitionId
     * @return
     */
    @RequestMapping(value = "/initworkflow")
    public String initworkflow(String processDefinitionId, Model model) {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();
        logger.info("流程定义KEY=" + processDefinition.getKey());
        List<UserTask> userTasks = userTaskService.findByWhere(processDefinitionId);
        logger.info(userTasks.size());
        logger.info(userTasks.size() == 0);
        if (userTasks.size() == 0) {
            userTaskService.loadSingleBpmn(processDefinitionId);
            logger.info("初始化节点成功！");
            userTasks = userTaskService.findByWhere(processDefinitionId);
        }
        model.addAttribute("procDefId", processDefinitionId);
        model.addAttribute("userTasks", userTasks);
        return "jsp/activiti/deploy/workflowconfig";
    }

    /**
     * 设置审批人员
     *
     * @param procDefId
     * @param request
     * @return
     */
    @RequestMapping("saveTaskNodeInfo")
    @ResponseBody
    public Object saveTaskNodeInfo(String procDefId, HttpServletRequest request) {
        List<UserTask> list = this.userTaskService.findByWhere(procDefId);
        for (UserTask userTask : list) {
            String taskDefKey = userTask.getTaskDefKey();
            String ids = request.getParameter(taskDefKey + "_id");
            String names = request.getParameter(taskDefKey + "_name");
            String taskType = request.getParameter(taskDefKey + "_taskType");
            String selectModel = request.getParameter(taskDefKey + "_selectModel");
            String taskCategory = request.getParameter(taskDefKey + "_taskCategory");
            String conditionId = request.getParameter(taskDefKey + "_conditionId");
            String conditionName = request.getParameter(taskDefKey + "_conditionName");
            System.out.println(ids);
            userTask.setTaskType(taskType);
            userTask.setCandidate_name(names);
            userTask.setCandidate_ids(ids);
            userTask.setSelectModel(selectModel);
            userTask.setTaskCategory(taskCategory);
            userTask.setConditionId(conditionId);
            userTask.setConditionName(conditionName);
            this.userTaskService.update(userTask);
        }
        return renderSuccess("设置审批人员成功！");
    }

    /**
     * 跳转待办任务、已完成任务页面
     *
     * @return
     */
    @RequestMapping(value = "/toDoUsertask")
    public String toDoUsertask() {
        return "jsp/activiti/task/taskList";
    }

    /**
     * 查询待办任务
     *
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/todoTask", method = {RequestMethod.POST})
    @ResponseBody
    public Object todoTask(@RequestParam(value = "page", required = false, defaultValue = "1") Integer page,
                           @RequestParam(value = "rows", required = false, defaultValue = "10") Integer rows,String userId) throws Exception {
        if (page < 1) {
            page = 1;
        }
        User user = userService.get(userId);
        Page<BaseVO> p = new Page<BaseVO>(page, rows);
        List<BaseVO> taskList = this.activitiService.findTodoTask(user, p);
        List<Object> jsonList = new ArrayList<Object>();
        for (BaseVO base : taskList) {
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("businessType", base.getBusinessType_());
            map.put("businessKey", base.getBusinessKey_());
            map.put("user_name", base.getUserName_());
            map.put("title", base.getTitle_());
            map.put("taskId", base.getTask().getId());
            map.put("taskName", base.getTask().getName());
            map.put("createTime", base.getTask().getCreateTime());
            String assign = base.getTask().getAssignee();
            if (assign != null) {
                User u = this.userService.get(assign);
                assign = u.getName();
            }
            String owner = base.getTask().getOwner();
            if (owner != null) {
                User u = this.userService.get(owner);
                owner = u.getName();
            }

            map.put("assign", assign);
            map.put("owner", owner);
            map.put("taskDefinitionKey", base.getTask().getTaskDefinitionKey());
            map.put("processInstanceId", base.getProcessInstance().getId());
            map.put("processDefinitionId", base.getProcessInstance().getProcessDefinitionId());
            map.put("processDefinitionKey", base.getProcessDefinition().getKey()); // 任务跳转用
            map.put("supended", base.getProcessInstance().isSuspended());
            map.put("version", base.getProcessDefinition().getVersion());
            map.put("status", base.getStatus_());
            //任务执行人
            String assigneeOrCandidateUser = (String) activitiService.findTodoTaskAssigneeOrCandidateUsers(base.getProcessInstance().getId())
                    .get("userNames");
            map.put("assigneeOrCandidateUser", assigneeOrCandidateUser);
            jsonList.add(map);
        }
        PageInfo pp = new PageInfo(page, rows);
        pp.setTotal(p.getTotal());
        pp.setRows(jsonList);
        return pp;
    }

    /**
     * 显示流程图,带流程跟踪
     *
     * @param processInstanceId
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "/showDiagram/{processInstanceId}", method = RequestMethod.GET)
    public void showDiagram(@PathVariable("processInstanceId") String processInstanceId, HttpServletResponse response)
            throws Exception {
        InputStream imageStream = this.activitiService.getDiagram(processInstanceId);
        // 输出资源内容到相应对象
        byte[] b = new byte[1024];
        int len;
        while ((len = imageStream.read(b, 0, 1024)) != -1) {
            response.getOutputStream().write(b, 0, len);
        }
    }

    /**
     * 显示流程图
     *
     * @param processInstanceId
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "/showDiagram_noTrace/{processInstanceId}", method = RequestMethod.GET)
    public String showDiagram_noTrace(@PathVariable("processInstanceId") String processInstanceId, HttpServletResponse response)
            throws Exception {
        HistoricProcessInstance pi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if (pi.getEndTime() == null) {
            //未完成流程
            return redirect("/process/showDiagram/" + processInstanceId);
        } else {
            //已完成流程
            return redirect("/process/process-definition?processDefinitionId=" + pi.getProcessDefinitionId() + "&resourceType=image");
        }
    }

    /**
     * 显示图片通过部署id，不带流程跟踪(没有乱码问题)
     *
     * @param processDefinitionId
     * @param resourceType        资源类型(xml|image)
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "/process-definition")
    public void loadByDeployment(@RequestParam("processDefinitionId") String processDefinitionId,
                                 @RequestParam("resourceType") String resourceType, HttpServletResponse response) throws Exception {
        InputStream resourceAsStream = this.activitiService.getDiagramByProDefinitionId_noTrace(resourceType,
                processDefinitionId);

        byte[] b = new byte[1024];
        int len = -1;
        while ((len = resourceAsStream.read(b, 0, 1024)) != -1) {
            response.getOutputStream().write(b, 0, len);
        }
    }

    /**
     * 显示图片通过流程id，不带流程跟踪(没有乱码问题)
     *
     * @param resourceType      资源类型(xml|image)
     * @param processInstanceId 流程实例ID
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "/process-instance")
    public void loadByProcessInstance(@RequestParam("resourceType") String resourceType,
                                      @RequestParam("processInstanceId") String processInstanceId, HttpServletResponse response)
            throws Exception {
        InputStream resourceAsStream = this.activitiService.getDiagramByProInstanceId_noTrace2(resourceType,
                processInstanceId);
        byte[] b = new byte[1024];
        int len = -1;
        while ((len = resourceAsStream.read(b, 0, 1024)) != -1) {
            response.getOutputStream().write(b, 0, len);
        }
    }

    /**
     * 跳转到已办流程页面
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/toTaskFinish")
    public String toTaskFinish(Model model) {
        return "jsp/activiti/task/taskfinish";
    }

    /**
     * 查看自己完成的任务
     *
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/myfinishedProcess")
    @ResponseBody
    public Object myfindFinishedProcessInstances(ProcessInstanceEntity processInstanceEntity,
            @RequestParam(value = "page", required = false) Integer page,
            @RequestParam(value = "rows", required = false) Integer rows) throws Exception {
        Page<BaseVO> p = new Page<BaseVO>(page, rows);
        List<Object> jsonList = new ArrayList<Object>();
        Map<String,Object>condition=new HashMap<String,Object>();
        String hasParams="";
        if(StringUtils.isNotNull(processInstanceEntity.getProcessInstanceId())) {
        	condition.put("processInstanceId", processInstanceEntity.getProcessInstanceId());
        	hasParams="1";
        }
        if(StringUtils.isNotNull(processInstanceEntity.getTitle())) {
        	condition.put("title", processInstanceEntity.getTitle());
        	hasParams="1";
        }
        if(StringUtils.isNotNull(processInstanceEntity.getUserid())) {
        	condition.put("userid", processInstanceEntity.getUserid());
        	hasParams="1";
        }
        if(StringUtils.isNotNull(processInstanceEntity.getBusinessKey())) {
        	condition.put("businessKey", processInstanceEntity.getBusinessKey());
        	hasParams="1";
        }
        if(StringUtils.isNotNull(processInstanceEntity.getStartTimeStart())) {
        	condition.put("startTimeStart", processInstanceEntity.getStartTimeStart());
        	hasParams="1";
        }
        if(StringUtils.isNotNull(processInstanceEntity.getStartTimeEnd())) {
        	condition.put("startTimeEnd", processInstanceEntity.getStartTimeEnd());
        	hasParams="1";
        }
        condition.put("hasParams", hasParams);
        p.setCondition(condition);
        User user = new User();
        user.setId(getUserId());
        List<BaseVO> processList = this.activitiService.findFinishedTaskInstancesPC(user, p);
        if (processList.size() > 0) {
            for (BaseVO base : processList) {
                Map<String, Object> map = new HashMap<String, Object>();
                map.put("processInstanceId", base.getProcessInstanceId_());
                //查询业务类型
                ProcessInstanceEntity processInstance = processInstanceEntityService.get(base.getProcessInstanceId_());
                map.put("businessType", processInstance.getBusinessType());
                map.put("businessKey", processInstance.getBusinessKey());
                map.put("user_name", processInstance.getUserName());
                map.put("title", processInstance.getTitle());
                map.put("startTime", base.getStartTime_());
                map.put("endTime", base.getEndTime_());
                map.put("deleteReason", base.getDeleteReason_());
                map.put("version", base.getVersion_());
                map.put("taskId", base.getTaskId());
                map.put("taskName", base.getTaskName());
                jsonList.add(map);
            }
        }
        PageInfo info = new PageInfo(page, rows);
        info.setTotal(p.getTotal());
        info.setRows(jsonList);
        return info;
    }



    /**
     * 跳转到查看批注页面
     *
     * @param processInstanceId
     * @param model
     * @return
     */
    @RequestMapping("/getCommentsByProcessInstanceId")
    public String getCommentsByProcessInstanceId(String processInstanceId, Model model) {
        List<CommentVO> comments = activitiService.getCommentsByProcessInstanceId(processInstanceId);
        model.addAttribute("comments", comments);
        model.addAttribute("processInstanceId",processInstanceId);
        return "jsp/activiti/task/comment";
    }

    /**
     * 查看批注
     * @param processInstanceId
     * @return
     */
    @ResponseBody
    @RequestMapping("queryComment")
    public Object queryComment(String processInstanceId){
        return commentEntityService.findComments(processInstanceId);
    }

    /**
     * 是否打印批注
     * @param id
     * @param print
     * @return
     */
    @ResponseBody
    @RequestMapping("updatePrint")
    public Object updatePrint(String id,Integer print){
        CommentEntity commentEntity= commentEntityService.get(id);
        commentEntity.setPrint(print);
        commentEntityService.update(commentEntity);
        return renderSuccess("设置成功");
    }
    /**
     * 跳转到流程监控页面
     *
     * @param model
     * @return
     */
    @RequestMapping("/toMonitor")
    public String toActivitiMonitor(Model model) {
        List<ProcessType> processTypes = processTypeService.findAll();
        model.addAttribute("processTypes", processTypes);
        return "jsp/activiti/task/taskmonitor";
    }
    
    /**
     * 跳转到我的申请
     * @param model
     * @return
     */
    @RequestMapping("/toMyApplay")
    public String toMyApplay(Model model) {
    	List<ProcessType> processTypes = processTypeService.findAll();
    	model.addAttribute("processTypes", processTypes);
    	model.addAttribute("userid", getUserId());
    	return "jsp/activiti/task/myapplay";
    }

    /**
     * 流程监控数据
     *
     * @param processInstance
     * @param page
     * @param rows
     * @return
     */
    @ResponseBody
    @RequestMapping("/activitiMonitorData")
    public Object activitiMonitorData(ProcessInstanceEntity processInstance, Integer page, Integer rows) {
        PageInfo info = new PageInfo(page, rows);
        Map<String, Object> condition = new HashMap<String, Object>();
        if (StringUtils.isNotNull(processInstance.getTitle())) {
            condition.put("title", processInstance.getTitle());
        }
        if (StringUtils.isNotNull(processInstance.getUserName())) {
            condition.put("userName", processInstance.getUserName());
        }
        if (StringUtils.isNotNull(processInstance.getUserid())) {
        	condition.put("userid", processInstance.getUserid());
        }
        if (StringUtils.isNotNull(processInstance.getBusinessKey())) {
            condition.put("businessKey", processInstance.getBusinessKey());
        }
        if (StringUtils.isNotNull(processInstance.getProcessInstanceId())) {
            condition.put("processInstanceId", processInstance.getProcessInstanceId());
        }
        if (StringUtils.isNotNull(processInstance.getStatus())) {
            condition.put("status", processInstance.getStatus());
        }
        if (StringUtils.isNotNull(processInstance.getStartTimeStart())) {
            condition.put("startTimeStart", processInstance.getStartTimeStart());
        }
        if (StringUtils.isNotNull(processInstance.getStartTimeEnd())) {
            condition.put("startTimeEnd", processInstance.getStartTimeEnd());
        }
        info.setCondition(condition);
        processInstanceEntityService.selectDataGrid(info);
        return info;
    }

    /****************************************************************************************/
    /**
     * 高亮显示追踪节点
     * @param processInstanceId
     * @param response
     * @throws Exception
     */
    @RequestMapping("graphHistoryProcessInstance")
    public void processTracking(String processInstanceId,HttpServletResponse response) throws Exception {
        HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        String procDefId = processInstance.getProcessDefinitionId();

        // 当前活动节点、活动线
        List<String> activeActivityIds = new ArrayList<>(), highLightedFlows;
        //所有的历史活动节点
        List<String> highLightedFinishes = new ArrayList<>();

        // 如果流程已经结束，则得到结束节点
        if (!isFinished(processInstanceId)) {
            // 如果流程没有结束，则取当前活动节点
            // 根据流程实例ID获得当前处于活动状态的ActivityId合集
            activeActivityIds = runtimeService.getActiveActivityIds(processInstanceId);
        }

        // 获得历史活动记录实体（通过启动时间正序排序，不然有的线可以绘制不出来）
        List<HistoricActivityInstance> historicActivityInstances = historyService
                .createHistoricActivityInstanceQuery().processInstanceId(processInstanceId)
                .orderByHistoricActivityInstanceStartTime().asc().list();

        for(HistoricActivityInstance historicActivityInstance : historicActivityInstances){
            highLightedFinishes.add(historicActivityInstance.getActivityId());
        }
        // 计算活动线
        highLightedFlows = getHighLightedFlows(
                (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
                        .getDeployedProcessDefinition(procDefId),
                historicActivityInstances);

        if (null != activeActivityIds) {
            InputStream imageStream = null;
            try {
                response.setContentType("image/png");

                // 获得流程引擎配置
                ProcessEngineConfiguration processEngineConfiguration = processEngine.getProcessEngineConfiguration();
                // 根据流程定义ID获得BpmnModel
                BpmnModel bpmnModel = repositoryService
                        .getBpmnModel(procDefId);
                // 输出资源内容到相应对象
                imageStream = new DefaultProcessDiagramGenerator().generateDiagram(
                        bpmnModel,
                        "png",
                        highLightedFinishes,
                        activeActivityIds,
                        highLightedFlows,
                        "宋体",
                        "宋体",
                        "宋体",
                        processEngineConfiguration.getClassLoader(),
                        1.0);

                int len;
                byte[] b = new byte[1024];

                while ((len = imageStream.read(b, 0, 1024)) != -1) {
                    response.getOutputStream().write(b, 0, len);
                }
            } finally {
                if(imageStream != null){
                    imageStream.close();
                }
            }
        }
    }

    public boolean isFinished(String processInstanceId) {
        return historyService.createHistoricProcessInstanceQuery().finished().processInstanceId(processInstanceId).count() > 0;
    }

    /**
     * @author H.J
     * @date 2018/4/9 10:29
     * @title getHighLightedFlows
     * @description: 获取流程应该高亮的线
     * @param processDefinitionEntity 流程定义实例
     * @param historicActivityInstances 流程活动节点实例
     * @return: java.util.List<java.lang.String>
     */
    public List<String> getHighLightedFlows(ProcessDefinitionEntity processDefinitionEntity,List<HistoricActivityInstance> historicActivityInstances) {

        List<String> highFlows = new ArrayList<>();// 用以保存高亮的线flowId
        List<String> highActivitiImpl = new ArrayList<>();

        for(HistoricActivityInstance historicActivityInstance : historicActivityInstances){
            highActivitiImpl.add(historicActivityInstance.getActivityId());
        }

        for(HistoricActivityInstance historicActivityInstance : historicActivityInstances){
            ActivityImpl activityImpl = processDefinitionEntity.findActivity(historicActivityInstance.getActivityId());
            List<PvmTransition> pvmTransitions = activityImpl.getOutgoingTransitions();
            // 对所有的线进行遍历
            for (PvmTransition pvmTransition : pvmTransitions) {
                // 如果取出的线的目标节点存在时间相同的节点里，保存该线的id，进行高亮显示
                ActivityImpl pvmActivityImpl = (ActivityImpl) pvmTransition.getDestination();
                if (highActivitiImpl.contains(pvmActivityImpl.getId())) {
                    highFlows.add(pvmTransition.getId());
                }
            }
        }

        return highFlows;
    }

    /****************************************************************************************/

    /**
     * 跳转到任务执行人页面
     * @param processInstanceId
     * @param model
     * @return
     */
    @RequestMapping("/toSetTaskAssignee")
    public String toSetTaskAssignee(String processInstanceId,Model model){
        List<Task>tasks=taskService.createTaskQuery().processInstanceId(processInstanceId).list();
        List<TaskVO>vos=new ArrayList<>();
        for(Task task:tasks){
           TaskVO vo=new TaskVO();
            if(StringUtils.isNotNull(task.getAssignee())){
                User user=userService.get(task.getAssignee());
                if(user!=null){
                   vo.setUserName(user.getName());
                   vo.setUserId(user.getId());
                }
            }
            vo.setTaskName(task.getName());
            vo.setTaskId(task.getId());
            vos.add(vo);
        }
        model.addAttribute("vos",vos);
        model.addAttribute("processInstanceId",processInstanceId);
        return "jsp/activiti/task/set_task_assignee";
    }

    /**
     * 设置任务执行人
     * @param processInstanceId
     * @return
     */
    @RequestMapping("/setTaskAssignee")
    @ResponseBody
    public Object setTaskAssignee(String processInstanceId,HttpServletRequest request){
        List<Task>tasks=taskService.createTaskQuery().processInstanceId(processInstanceId).list();
        logger.info("流程ID={}",processInstanceId);
        for (int i=0;i<tasks.size();i++){
            String assignee=request.getParameter("userId_"+tasks.get(i).getId());
            if(StringUtils.isNotNull(assignee)) {
                saveOperation(tasks.get(i),assignee);
                tasks.get(i).setAssignee(assignee);
                taskService.saveTask(tasks.get(i));
            }
        }
        return renderSuccess("设置成功！");
    }

    /**
     * 保存设置任务执行人操作行为
     * @param task
     * @param userId
     */
    protected void saveOperation(Task task,String userId){
        CommentEntity commentEntity=new CommentEntity();
        commentEntity.setType("setTaskAssignee");
        commentEntity.setTime(new Date());
        String sourceUserName="";
        String newUserName="";
        commentEntity.setTaskId(task.getId());
        commentEntity.setTaskName(task.getName());
        if(StringUtils.isNotNull(task.getAssignee())) {
        	User user=userService.get(task.getAssignee());
        	if(user!=null) {
        		sourceUserName=user.getName();
        	}
        	if(StringUtils.isNotNull(userId)) {
        		User newUser=userService.get(userId);
        		if(newUser!=null) {
        			newUserName=user.getName();
            	}
        	}
        }
        String comment="设置审批执行人！原任务执行人【"+sourceUserName+"】设置为【"+newUserName+"】";
        commentEntity.setComment(comment);
        commentEntity.setProcessInstanceId(task.getProcessInstanceId());
        commentEntity.setUserid(getUserId());
        commentEntity.setUserName(getStaffName());
        commentEntityService.save(commentEntity);
    }
}
